﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Data;
using ICSharpCode.SharpZipLib.Zip;

namespace Business.Common.Utils
{
    public static class Compression
    {
        private static object lockCompressObject = new object();
        private static object lockDecompressObject = new object();
        private static object lCompressObject = new object();
        private static object lDecompressObject = new object();

        public static byte[] CompressDataSet(DataSet ds)
        {
            if (ds == null)
            {
                throw new Exception("The data set must be not null!");
            }
            lock (lockCompressObject)
            {
                ds.RemotingFormat = SerializationFormat.Binary;
                BinaryFormatter bf = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                bf.Serialize(ms, ds);
                return Compress(ms.ToArray(), 9);
            }
        }

        public static byte[] CompressObj(Object obj)
        {
            if (obj == null)
            {
                throw new Exception("The object must be not null!");
            }
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            bf.Serialize(ms, obj);
            return Compress(ms.ToArray(), 9);
        }

        public static object DecompressObj(byte[] bytData)
        {
            object resObj = new object();
            byte[] b = Decompress(bytData);
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            ms.Write(b, 0, b.Length);
            ms.Seek(0, 0);
            resObj = bf.Deserialize(ms);
            return resObj;
        }


        public static DataSet DecompressDataSet(byte[] bytData)
        {
            lock (lockDecompressObject)
            {
                DataSet ds = new DataSet();
                ds.RemotingFormat = SerializationFormat.Binary;
                byte[] b = Decompress(bytData);
                BinaryFormatter bf = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                ms.Write(b, 0, b.Length);
                ms.Seek(0, 0);
                ds = (DataSet)bf.Deserialize(ms);
                return ds;
            }
        }

        private static byte[] Compress(byte[] bytData, params int[] ratio)
        {
            lock (lCompressObject)
            {
                int compRatio = 9;
                if (ratio[0] > 0)
                {
                    compRatio = ratio[0];
                }
                try
                {
                    MemoryStream ms = new MemoryStream();
                    ICSharpCode.SharpZipLib.Zip.Compression.Deflater defl = new ICSharpCode.SharpZipLib.Zip.Compression.Deflater(compRatio, false);
                    Stream s = new ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream(ms, defl);
                    s.Write(bytData, 0, bytData.Length);
                    s.Close();
                    byte[] compressedData = (byte[])ms.ToArray();
                    return compressedData;
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }

        private static byte[] Decompress(byte[] bytInput)
        {
            lock (lDecompressObject)
            {
                MemoryStream ms = new MemoryStream(bytInput, 0, bytInput.Length);
                byte[] bytResult = null;
                string strResult = String.Empty;
                Stream s2 = new ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream(ms);
                try
                {
                    bytResult = ReadFullStream(s2);
                    s2.Close();
                    s2 = null;
                }
                catch (Exception)
                {
                    //additional handling
                    throw;
                }
                return bytResult;
            }
        }

        private static byte[] ReadFullStream(Stream stream)
        {
            try
            {
                byte[] buffer = new byte[32768];
                using (MemoryStream ms = new MemoryStream())
                {
                    while (true)
                    {
                        int read = stream.Read(buffer, 0, buffer.Length);
                        if (read <= 0)
                        {
                            buffer = null;
                            return ms.ToArray();
                        }
                        ms.Write(buffer, 0, read);
                    }
                }
            }
            catch (Exception)
            {
                //additional handling
                throw;
            }
        }

        public static bool Unzip(string source, string destination, string dirFilter)
        {
            if (!(File.Exists(source)))
                return false;
            if (!(Directory.Exists(destination)))
                return false;
            try
            {
                FastZip unzip = new FastZip();
                unzip.ExtractZip(source, destination, FastZip.Overwrite.Always, null, "", dirFilter, true);
            }
            catch (Exception)
            {
                //additional handling
                throw;
            }
            return true;
        }

        public static bool Zip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)
        {
            if (!(Directory.Exists(sourceDirectory)))
                return false;
            try
            {
                FastZip zip = new FastZip();
                zip.CreateZip(zipFileName, sourceDirectory, recurse,fileFilter);
            }
            catch (Exception)
            {
                //additional handling
                throw ;
            }
            return true;
        }

        
    }
}
